package com.leyantech.ecp.agenx.common.utils;

import com.leyantech.ai.FAQDetail;
import com.leyantech.ai.H2HDetail;
import com.leyantech.ai.PolicyDetail;
import com.leyantech.ai.WaitDetail;
import com.leyantech.ai.WorkFlowDetail;
import com.leyantech.marketing.packet.proto.pdd.PddMarketingContextPacket;
import com.leyantech.utility.config.ConfigUtil;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.GeneratedMessageV3;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.Printer;
import com.google.protobuf.util.JsonFormat.TypeRegistry;
import com.google.protobuf.util.JsonFormat.TypeRegistry.Builder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.reflections.Reflections;

import java.util.Set;
import java.util.function.Supplier;

/**
 * @author eahau, {@literal <eahau@foxmail.com>}
 * @date 2022-12-19.
 */
@Slf4j
public class PbPrintHelper {

  static final Supplier<Printer> printer = ConfigUtil.getDynamicConfig(
      "protobuf.log.class.set",
      json -> {
        final Set<String> classNameSet = Sets.newHashSet(JsonUtils.fromJson(json, String[].class));

        final Builder builder = TypeRegistry.newBuilder();
        for (String classNameOrPackage : classNameSet) {
          new Reflections(classNameOrPackage)
              .getSubTypesOf(GeneratedMessageV3.class)
              .forEach(clz -> {
                try {
                  final Descriptor descriptor = (Descriptor) MethodUtils
                      .invokeStaticMethod(clz, "getDescriptor", null);
                  builder.add(descriptor);
                } catch (Exception e) {
                  log.error("cannot found class {}", classNameOrPackage);
                }
              });
        }

        return JsonFormat.printer()
            .omittingInsignificantWhitespace()
            .usingTypeRegistry(builder.build());
      },
      JsonFormat.printer()
          .omittingInsignificantWhitespace()
          .usingTypeRegistry(
              TypeRegistry.newBuilder()
                  .add(Lists.newArrayList(
                      PolicyDetail.getDescriptor(), FAQDetail.getDescriptor(),
                      WorkFlowDetail.getDescriptor(), H2HDetail.getDescriptor(),
                      WaitDetail.getDescriptor(), PddMarketingContextPacket.getDescriptor()
                      )
                  )
                  .build()
          )
  );

  private PbPrintHelper() {
  }

  public static String toJson(MessageOrBuilder message) {
    try {
      return printer.get().print(message);
    } catch (InvalidProtocolBufferException e) {
      log.warn("invalid protobuf", e);
      return message.toString();
    }
  }

  public static Object lazyToJson(MessageOrBuilder message) {
    return new Object() {
      @Override
      public String toString() {
        return PbPrintHelper.toJson(message);
      }
    };
  }

}
